package com.navinfo.platform.score.service.impl;

import com.navinfo.platform.score.enums.LoadStatusEnum;
import com.navinfo.platform.score.enums.ScoreLevelEnum;
import com.navinfo.platform.score.enums.ScoreModelEnum;
import com.navinfo.platform.score.pojo.ScoreEntry;
import com.navinfo.platform.score.pojo.ScoreWeight;
import com.navinfo.platform.score.pojo.ScoreWeightCompiled;
import com.navinfo.platform.score.service.ScoreAlgorithmChainService;
import com.navinfo.tripanalysis.common.arithmetic.common.ExtraStatisticData;
import com.navinfo.tripanalysis.common.arithmetic.common.OuterStatisticData;
import com.navinfo.tripanalysis.common.util.BigDecimalUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.Serializable;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 行程打分算法连
 *
 * @author CAI
 */
public class ScoreAlgorithmChainServiceImpl implements ScoreAlgorithmChainService, Serializable {
    private Map<String, ScoreWeightCompiled> broadcastScoreWeight;
    static final Logger logger = LoggerFactory.getLogger(ScoreAlgorithmChainServiceImpl.class);

    @Override
    public List<ScoreEntry> calTripScore(OuterStatisticData tripData, LoadStatusEnum status, ExtraStatisticData extraData){
        Map<String, ScoreWeightCompiled> algorithmChain = broadcastScoreWeight;
        Double totleScore = 0.00;
        Double safeScore = 0.00;
        Double ecoScore = 0.00;
        BigDecimal safeWeight = new BigDecimal(0);
        BigDecimal ecoWeight = new BigDecimal(0);
        //新增测试
        BigDecimal safeScoreDec = new BigDecimal(0);
        BigDecimal ecoScoreDec = new BigDecimal(0);

        String modelType;
        String level;
        String level1;
        String level2;
        BigDecimal weight;
        String type = status.getType();
        boolean environmentSwitch = true;
        if(extraData == null){
            environmentSwitch = false;
        }
        List<ScoreEntry> result = new ArrayList<>();
        for (Map.Entry<String, ScoreWeightCompiled> entry : algorithmChain.entrySet()) {
            String key = entry.getKey();
            String _loadType = key.split("_")[0];
            if(type.equals(_loadType)){//判断相应的载重状态
                ScoreWeight scoreWeight = entry.getValue().getScoreWeight();
                modelType = scoreWeight.getModelType();// 指标类型
                level = scoreWeight.getType();
                level1 = scoreWeight.getLevel1();
                level2 = scoreWeight.getLevel2();
                weight = scoreWeight.getWeight();
                if(!environmentSwitch){
                    if(ScoreLevelEnum.SAFE_LEVEL_ENV.getType().equals(level1)){
                        continue;
                    }
                }
                logger.info("得分计算开始.....");
                Double score = calScore(modelType, entry.getValue(), tripData, extraData);
                if(score == null) continue;
                // 安全评分
                if(ScoreLevelEnum.SAFE_LEVEL.getType().equals(level)){
                    //safeScore += score * weight.doubleValue();
                    //safeScore += weight.multiply(new BigDecimal(score)).doubleValue();
                    //safeWeight = safeWeight.add(weight);
                    safeScoreDec = safeScoreDec.add(weight.multiply(new BigDecimal(score)));
                    safeWeight = safeWeight.add(weight);
//                    totleSafeWeight += weight;
                    logger.info(" 安全分数{}={}, weight={}, 总分={}",modelType, score, weight, safeScoreDec);
                } else {// 经济评分
                    //ecoScore += weight.multiply(new BigDecimal(score)).doubleValue();
                    //ecoWeight = ecoWeight.add(weight);
                    ecoScoreDec = ecoScoreDec.add(weight.multiply(new BigDecimal(score)));
                    ecoWeight = ecoWeight.add(weight);
                    logger.info(" 经济分数{}={}, weight={}, 总分={}",modelType, score, weight, ecoScoreDec);
                }
                // 单项得分
                ScoreEntry scoreEntry = new ScoreEntry();
                scoreEntry.setType(level2);
                scoreEntry.setModel(modelType);
                scoreEntry.setScore(score.intValue());
                result.add(scoreEntry);
            }
        }
        // 综合得分
        //totleScore = (safeScore + ecoScore)/(safeWeight.add(ecoWeight).doubleValue());
        totleScore = safeScoreDec.add(ecoScoreDec).divide(safeWeight.add(ecoWeight),10,BigDecimal.ROUND_HALF_UP).doubleValue();
        // 安全单项得分
        //safeScore = safeScore / safeWeight.doubleValue();
        safeScore = safeScoreDec.divide(safeWeight,10,BigDecimal.ROUND_HALF_UP).doubleValue();
        // 经济单项得分
        //ecoScore = ecoScore / ecoWeight.doubleValue();
        ecoScore = ecoScoreDec.divide(ecoWeight,10,BigDecimal.ROUND_HALF_UP).doubleValue();
        logger.info(" 综合得分={}+{}/({}+{})", safeScore, ecoScore, safeWeight.doubleValue(), ecoWeight.doubleValue());
        logger.info(" 安全单项得分={}/{}", safeScore, safeWeight.doubleValue());
        logger.info(" 经济单项得分={}/{}", ecoScore, ecoWeight.doubleValue());

        logger.info("打分计算结束........");

        ScoreEntry scoreEntry = new ScoreEntry();
        scoreEntry.setType(ScoreLevelEnum.SCORE.getType());
        scoreEntry.setScore(totleScore.intValue());
        result.add(scoreEntry);
        scoreEntry = new ScoreEntry();
        scoreEntry.setType(ScoreLevelEnum.SAFE_LEVEL.getType());
        scoreEntry.setScore(safeScore.intValue());
        result.add(scoreEntry);
        scoreEntry = new ScoreEntry();
        scoreEntry.setType(ScoreLevelEnum.ECO_LEVEL.getType());
        scoreEntry.setScore(ecoScore.intValue());
        result.add(scoreEntry);
//        result.put("totleScore",totleScore.intValue());
//        result.put("safeScore",safeScore.intValue());
//        result.put("ecoScore",ecoScore.intValue());
        return result;
    }

    public Map<String, ScoreWeightCompiled> getBroadcastScoreWeight() {
        return broadcastScoreWeight;
    }

    public void setBroadcastScoreWeight(Map<String, ScoreWeightCompiled> broadcastScoreWeight) {
        this.broadcastScoreWeight = broadcastScoreWeight;
    }

    /**
     * 计算指标分数
     * @param modelType 指标类型
     * @param compiled 计算公式
     * @param tripData 行程数据
     * @return 指标分数
     */
    private Double calScore(String modelType, ScoreWeightCompiled compiled, OuterStatisticData tripData, ExtraStatisticData extraData){
        ScoreModelEnum modelEnum = ScoreModelEnum.getEnum(modelType);
        if(modelEnum == null) return 0.0;
        Double score = 0.0;
        switch (modelEnum){
            // 疲劳驾驶
            case fatigueDriving:
                score = fatigueDriving(compiled, tripData);
                break;
            // 急加速
            case sharpAcceleration:
                score = sharpAcceleration(compiled, tripData, extraData);
                break;
            // 急减速
            case sharpDeceleration:
                score = sharpDeceleration(compiled, tripData, extraData);
                break;
            // 急踩油门
            case sharpStepOnAccelerator:
                score = sharpStepOnAccelerator(compiled, tripData);
                break;
            // 超速
            case vehicleOverSpeed:
                score = vehicleOverSpeed(compiled, tripData);
                break;
            // 怠速
            case vehicleParkingIdle:
                score = vehicleParkingIdle(compiled, tripData);
                break;
            // 空挡滑行
            case idlingSlide:
                score = idlingSlide(compiled, tripData);
                break;
            // 经济驾驶
            case ecoDriving:
                score = ecoDriving(compiled, tripData);
                break;
            // 行驶过程中手刹使用
            case runingHandbrake:
                score = runingHandbrake(compiled, tripData);
                break;
            // 超转速
            case engineOverSpeed:
                score = engineOverSpeed(compiled, tripData);
                break;
            // 冷引擎启动
            case coldEngineStart:
                score = coldEngineStart(compiled, tripData);
                break;
            // 停车轰油门
            case parkingStepOnAccelerator:
                score = parkingStepOnAccelerator(compiled, tripData);
                break;
            // 车辆起步
            case vehicleStart:
                score = vehicleStart(compiled, tripData);
                break;
            // 加速度标准差
            case accelerationDeviation:
                score = accelerationDeviation(compiled, tripData, extraData);
                break;
            // 车速标准差
            case speedDeviation:
                score = speedDeviation(compiled, tripData, extraData);
                break;
            // 转速区间
            case rotationRange:
                score = rotationRange(compiled, tripData);
                break;
            // 速度区间
            case speedRange:
                score = speedRange(compiled, tripData);
                break;
            // 档位
            case gears:
                score = gears(compiled, tripData);
                break;
            // 同车型油耗
            case carTypeFule:
                score = carTypeFule(compiled, tripData);
                break;
            default:
                break;
        }
        //if(score == null || score < 0) return 0.0;
        return score;
    }
    // 疲劳驾驶
    private Double fatigueDriving(ScoreWeightCompiled compiled, OuterStatisticData tripData){
        if(tripData.getFatigueDrivingNumber() == null) return null;
        Map<String, Object> env = new HashMap<>();
        ScoreWeight sw = compiled.getScoreWeight();
        // 疲劳驾驶次数
        env.put(sw.getParam1(), tripData.getFatigueDrivingNumber());
        return (Double) compiled.getExpression().execute(env);
    }
    // 急加速
    private Double sharpAcceleration(ScoreWeightCompiled compiled, OuterStatisticData tripData, ExtraStatisticData extraData){
        Map<String, Object> env = new HashMap<>();
        ScoreWeight sw = compiled.getScoreWeight();
        Double times = null;
        Integer _time = null;
        if(ScoreLevelEnum.SAFE_LEVEL_ENV.getType().equals(sw.getLevel1())){
            ScoreLevelEnum level2 = ScoreLevelEnum.getEnum(sw.getLevel2());
            switch (level2){
                    // 恶劣天气
                case SAFE_LEVEL_ENV_BAD_WEATHER:
                    _time = extraData.getBwSharpAccelerationPer100KM();
                    break;
                    // 危险路段
                case SAFE_LEVEL_ENV_DANGEROUS:
                    _time = extraData.getDrSharpAccelerationPer100KM();
                    break;
                    // 拥堵路段
                case SAFE_LEVEL_ENV_TRAFFIC:
                    _time = extraData.getTjSharpAccelerationPer100KM();
                    break;
                    // 高原路段
                case SAFE_LEVEL_ENV_PLATEAU:
                    _time = extraData.getPtSharpAccelerationPer100KM();
                    break;
                    // 夜晚时段
                case SAFE_LEVEL_ENV_NIGHT:
                    _time = extraData.getNtSharpAccelerationPer100KM();
                    break;
            }
            if(_time == null) return null;
            times = Double.valueOf(_time);
        } else {
            if(tripData.getSharpUpSpeedNumber() == null || tripData.getTripMileage() == null || tripData.getTripMileage() == 0) return null;
            //times = Math.round(tripData.getSharpUpSpeedNumber() / (tripData.getTripMileage() * 0.01));
            times = divide(tripData.getSharpUpSpeedNumber(), tripData.getTripMileage() * 0.01 * 0.001);
        }
        // 急加速 百公里使用次数
        env.put(sw.getParam1(), times);
        return (Double) compiled.getExpression().execute(env);
    }
    // 急减速
    private Double sharpDeceleration(ScoreWeightCompiled compiled, OuterStatisticData tripData, ExtraStatisticData extraData){
        Map<String, Object> env = new HashMap<>();
        ScoreWeight sw = compiled.getScoreWeight();
        Double times = null;
        Integer _time = null;
        if(ScoreLevelEnum.SAFE_LEVEL_ENV.getType().equals(sw.getLevel1())){
            ScoreLevelEnum level2 = ScoreLevelEnum.getEnum(sw.getLevel2());
            switch (level2){
                // 恶劣天气
                case SAFE_LEVEL_ENV_BAD_WEATHER:
                    _time = extraData.getBwSharpDecelerationPer100KM();
                    break;
                // 危险路段
                case SAFE_LEVEL_ENV_DANGEROUS:
                    _time = extraData.getDrSharpDecelerationPer100KM();
                    break;
                // 拥堵路段
                case SAFE_LEVEL_ENV_TRAFFIC:
                    _time = extraData.getTjSharpDecelerationPer100KM();
                    break;
                // 高原路段
                case SAFE_LEVEL_ENV_PLATEAU:
                    _time = extraData.getPtSharpDecelerationPer100KM();
                    break;
                // 夜晚时段
                case SAFE_LEVEL_ENV_NIGHT:
                    _time = extraData.getNtSharpDecelerationPer100KM();
                    break;
            }
            if(_time == null) return null;
            times = Double.valueOf(_time);
        } else {
            if(tripData.getSharpDownSpeedNumber() == null || tripData.getTripMileage() == null || tripData.getTripMileage() == 0) return null;
//            times = Math.round(tripData.getSharpDownSpeedNumber() / (tripData.getTripMileage() * 0.01));
            times = divide(tripData.getSharpDownSpeedNumber(), tripData.getTripMileage() * 0.01 * 0.001);
        }
        // 急减速 百公里使用次数
        env.put(sw.getParam1(), times);
        return (Double) compiled.getExpression().execute(env);
    }

    // 急踩油门
    private Double sharpStepOnAccelerator(ScoreWeightCompiled compiled, OuterStatisticData tripData){
        Map<String, Object> env = new HashMap<>();
        ScoreWeight sw = compiled.getScoreWeight();
        Integer times = tripData.getSharpStepOnGasNumber();
        Integer mileage = tripData.getTripMileage();
        if(times == null || mileage == null || mileage == 0) return null;
        // 急踩油门 百公里使用次数
       // env.put(sw.getParam1(), Math.round(times / (mileage * 0.01) * 10) * 0.1);
        env.put(sw.getParam1(), divide(times ,mileage * 0.01 * 0.001));
        return (Double) compiled.getExpression().execute(env);
    }

    // 超速 TODO 只有90，120的次数
    private Double vehicleOverSpeed(ScoreWeightCompiled compiled, OuterStatisticData tripData){
        Map<String, Object> env = new HashMap<>();
        ScoreWeight sw = compiled.getScoreWeight();
        Integer mileage = tripData.getTripMileage();
        if(tripData.getSo90Number() == null || tripData.getSo120Number() == null || mileage == null || mileage == 0) return null;
        Integer times = tripData.getSo90Number() + tripData.getSo120Number();
        // 超速次数
        env.put(sw.getParam1(), divide(times ,mileage * 0.01 * 0.001));
        return (Double) compiled.getExpression().execute(env);
    }
    // 怠速
    private Double vehicleParkingIdle(ScoreWeightCompiled compiled, OuterStatisticData tripData){
        Map<String, Object> env = new HashMap<>();
        ScoreWeight sw = compiled.getScoreWeight();
        Integer idleDuration = tripData.getIdleDuration();
        Integer tripDuration = tripData.getTripDuration();
        if(idleDuration == null || tripDuration == null || tripDuration == 0 ) return null;
        // 怠速 时长占比
//        env.put(sw.getParam1(), Math.round(idleDuration / tripDuration * 10) * 0.1);
        env.put(sw.getParam1(), divide(idleDuration ,tripDuration));
        return (Double) compiled.getExpression().execute(env);
    }
    // 空挡滑行
    private Double idlingSlide(ScoreWeightCompiled compiled, OuterStatisticData tripData){
        Map<String, Object> env = new HashMap<>();
        ScoreWeight sw = compiled.getScoreWeight();
        Integer times = tripData.getNeutralGearCoastNumber();
        Integer mileage = tripData.getTripMileage();
        if(times == null || mileage == null || mileage == 0 ) return null;
        // 空挡滑行 百公里使用次数
        env.put(sw.getParam1(), divide(times ,mileage * 0.01 * 0.001));
        return (Double) compiled.getExpression().execute(env);
    }
    // 经济驾驶
    private Double ecoDriving(ScoreWeightCompiled compiled, OuterStatisticData tripData){
        Map<String, Object> env = new HashMap<>();
        ScoreWeight sw = compiled.getScoreWeight();
        Integer ecoRpmPercent = tripData.ecoProportion();
        if(ecoRpmPercent == null) return null;
        // 经济驾驶 时长占比
        env.put(sw.getParam1(), ecoRpmPercent * 0.01);
        return (Double) compiled.getExpression().execute(env);
    }
    // 行驶过程中手刹使用
    private Double runingHandbrake(ScoreWeightCompiled compiled, OuterStatisticData tripData){
        Map<String, Object> env = new HashMap<>();
        ScoreWeight sw = compiled.getScoreWeight();
        if(tripData.getDrivingHandbrakeNumber() == null) return null;
        // 行驶过程中手刹使用次数
        env.put(sw.getParam1(), tripData.getDrivingHandbrakeNumber());
        return (Double) compiled.getExpression().execute(env);
    }
    // 超转速
    private Double engineOverSpeed(ScoreWeightCompiled compiled, OuterStatisticData tripData){
        Map<String, Object> env = new HashMap<>();
        ScoreWeight sw = compiled.getScoreWeight();
        Integer duration = tripData.getSrDuration();
        Integer tripDuration = tripData.getTripDuration();
        if(duration == null || tripDuration == null || tripDuration == 0) return null;
        // 超转速 时长占比

//        env.put(sw.getParam1(), Math.round(Double.valueOf(duration) / Double.valueOf(tripDuration) * 10) * 0.1);
        env.put(sw.getParam1(), divide(duration ,tripDuration));
        return (Double) compiled.getExpression().execute(env);
    }
    // 冷引擎启动
    private Double coldEngineStart(ScoreWeightCompiled compiled, OuterStatisticData tripData){
        Map<String, Object> env = new HashMap<>();
        ScoreWeight sw = compiled.getScoreWeight();
        if(tripData.getVehicleColdStartNumber() == null) return null;
        // 冷引擎启动次数
        env.put(sw.getParam1(), tripData.getVehicleColdStartNumber());
        return (Double) compiled.getExpression().execute(env);
    }
    // 停车轰油门
    private Double parkingStepOnAccelerator(ScoreWeightCompiled compiled, OuterStatisticData tripData){
        Map<String, Object> env = new HashMap<>();
        ScoreWeight sw = compiled.getScoreWeight();
        if(tripData.getParkThrottleDuration() == null) return null;
        // 停车轰油门时长
        env.put(sw.getParam1(), tripData.getParkThrottleDuration());
        return (Double) compiled.getExpression().execute(env);
    }
    // 车辆起步
    private Double vehicleStart(ScoreWeightCompiled compiled, OuterStatisticData tripData){
        Map<String, Object> env = new HashMap<>();
        ScoreWeight sw = compiled.getScoreWeight();
        Integer times = tripData.getVehicleStartNumber();
        Integer mileage = tripData.getTripMileage();
        if(times == null || mileage == null || mileage == 0) return null;
        // 车辆起步 百公里次数
//        env.put(sw.getParam1(), Math.round(times / (mileage * 0.01) * 10) * 0.1);
        env.put(sw.getParam1(), divide(times ,mileage * 0.01 * 0.001));
        return (Double) compiled.getExpression().execute(env);
    }
    // 加速度标准差
    private Double accelerationDeviation(ScoreWeightCompiled compiled, OuterStatisticData tripData, ExtraStatisticData extraData){
        if(extraData == null || extraData.getAccelerationDeviation() == null) return null;
        Map<String, Object> env = new HashMap<>();
        ScoreWeight sw = compiled.getScoreWeight();
        // 加速度标准差
        env.put(sw.getParam1(), extraData.getAccelerationDeviation());
        return (Double) compiled.getExpression().execute(env);
    }
    // 车速标准差
    private Double speedDeviation(ScoreWeightCompiled compiled, OuterStatisticData tripData, ExtraStatisticData extraData){
        if(extraData == null) return null;
        Map<String, Object> env = new HashMap<>();
        ScoreWeight sw = compiled.getScoreWeight();
        Integer speedDeviation = 0;
        if(ScoreLevelEnum.SAFE_LEVEL_ENV.getType().equals(sw.getLevel1())){
            ScoreLevelEnum level2 = ScoreLevelEnum.getEnum(sw.getLevel2());
            switch (level2){
                // 恶劣天气
                case SAFE_LEVEL_ENV_BAD_WEATHER:
                    speedDeviation = extraData.getBwSpeedDeviation();
                    break;
                // 危险路段
                case SAFE_LEVEL_ENV_DANGEROUS:
                    speedDeviation = extraData.getDrSpeedDeviation();
                    break;
                // 拥堵路段
                case SAFE_LEVEL_ENV_TRAFFIC:
                    speedDeviation = extraData.getTjSpeedDeviation();
                    break;
                // 高原路段
                case SAFE_LEVEL_ENV_PLATEAU:
                    speedDeviation = extraData.getPtSpeedDeviation();
                    break;
                // 夜晚时段
                case SAFE_LEVEL_ENV_NIGHT:
                    speedDeviation = extraData.getNtSpeedDeviation();
                    break;
            }
        } else {
            speedDeviation = extraData.getSpeedDeviation();
        }
        if(speedDeviation == null) return null;
        // 车速标准差
        env.put(sw.getParam1(), speedDeviation);
        return (Double) compiled.getExpression().execute(env);
    }
    // 转速区间
    private Double rotationRange(ScoreWeightCompiled compiled, OuterStatisticData tripData){
        Map<String, Object> env = new HashMap<>();
        ScoreWeight sw = compiled.getScoreWeight();
        // 转速区间1~6
        // 500~800(1速)
        Integer rpmRange1 = plus(tripData.getRpmRange600Duration(),tripData.getRpmRange700Duration(),tripData.getRpmRange800Duration());
        // 800~1100(2速)
        Integer rpmRange2 = plus(tripData.getRpmRange900Duration(),tripData.getRpmRange1000Duration(),tripData.getRpmRange1100Duration());
        // 1100~1700(3速)
        Integer rpmRange3 = plus(tripData.getRpmRange1200Duration(),tripData.getRpmRange1300Duration(),tripData.getRpmRange1400Duration()
                ,tripData.getRpmRange1500Duration(),tripData.getRpmRange1600Duration(),tripData.getRpmRange1700Duration());

        // 1700~2000(4速)
        Integer rpmRange4 = plus(tripData.getRpmRange1800Duration(),tripData.getRpmRange1900Duration(),tripData.getRpmRange2000Duration());
        // 2000~2300(5速)
        Integer rpmRange5 = plus(tripData.getRpmRange2100Duration(),tripData.getRpmRange2200Duration(),tripData.getRpmRange2300Duration());
        // >2300(6速)

        Integer rpmRange6 = plus(tripData.getRpmRange2400Duration(),tripData.getRpmRange2500Duration(),tripData.getRpmRange2600Duration()
                ,tripData.getRpmRange2700Duration(),tripData.getRpmRange2800Duration(),tripData.getRpmRange2900Duration(),tripData.getRpmRange3000Duration()
                , tripData.getRpmRangeOver3000Duration());

        Integer tripDuration = tripData.getTripDuration();
        if((rpmRange1 == null && rpmRange2  == null && rpmRange3  == null && rpmRange4  == null
                && rpmRange5  == null && rpmRange6 == null) || tripDuration == null || tripDuration == 0) return null;
//        env.put(sw.getParam1(), Math.round(rpmRange1 / tripDuration * 10) * 0.1);
//        env.put(sw.getParam2(), Math.round(rpmRange2 / tripDuration * 10) * 0.1);
//        env.put(sw.getParam3(), Math.round(rpmRange3 / tripDuration * 10) * 0.1);
//        env.put(sw.getParam4(), Math.round(rpmRange4 / tripDuration * 10) * 0.1);
//        env.put(sw.getParam5(), Math.round(rpmRange5 / tripDuration * 10) * 0.1);
//        env.put(sw.getParam6(), Math.round(rpmRange6 / tripDuration * 10) * 0.1);
        env.put(sw.getParam1(), divide(rpmRange1, tripDuration));
        env.put(sw.getParam2(), divide(rpmRange2, tripDuration));
        env.put(sw.getParam3(), divide(rpmRange3, tripDuration));
        env.put(sw.getParam4(), divide(rpmRange4, tripDuration));
        env.put(sw.getParam5(), divide(rpmRange5, tripDuration));
        env.put(sw.getParam6(), divide(rpmRange6, tripDuration));
        return (Double) compiled.getExpression().execute(env);
    }
    // 速度区间
    private Double speedRange(ScoreWeightCompiled compiled, OuterStatisticData tripData){
        Map<String, Object> env = new HashMap<>();
        ScoreWeight sw = compiled.getScoreWeight();
        // 速度区间1~6
        // 速度区间1速  ：0（怠速）km/h(1速)
        Integer speedRange1 = tripData.getIdleDuration();
        // 1<= X<=30  km/h(2速) TODO getSpeedRange01Duration 中包含怠速时间？
        Integer speedRange2 = plus(tripData.getSpeedRange01Duration(), tripData.getSpeedRange02Duration(), tripData.getSpeedRange03Duration());
        // 31<= X<=60  km/h(3速)
        Integer speedRange3 = plus(tripData.getSpeedRange04Duration()
                , tripData.getSpeedRange05Duration()
                , tripData.getSpeedRange06Duration());
        // 61<= X<=80  km/h(4速)
        Integer speedRange4 = plus(tripData.getSpeedRange07Duration()
                , tripData.getSpeedRange08Duration());
        // 81<= X<=100  km/h(5速)
        Integer speedRange5 = plus(tripData.getSpeedRange09Duration()
                , tripData.getSpeedRange10Duration());
        // 100<X km/h(6速)
        Integer speedRange6 = plus(tripData.getSpeedRange11Duration()
                , tripData.getSpeedRange12Duration()
                , tripData.getExceedSpeedRangeDuration());
        Integer tripDuration = tripData.getTripDuration();
        if((speedRange1 == null && speedRange2 == null && speedRange3 == null && speedRange4 == null
                && speedRange5 == null && speedRange6 == null) || tripDuration == null || tripDuration == 0) return null;
//        env.put(sw.getParam1(), Math.round(speedRange1 / tripDuration * 10) * 0.1);
//        env.put(sw.getParam2(), Math.round(speedRange2 / tripDuration * 10) * 0.1);
//        env.put(sw.getParam3(), Math.round(speedRange3 / tripDuration * 10) * 0.1);
//        env.put(sw.getParam4(), Math.round(speedRange4 / tripDuration * 10) * 0.1);
//        env.put(sw.getParam5(), Math.round(speedRange5 / tripDuration * 10) * 0.1);
//        env.put(sw.getParam6(), Math.round(speedRange6 / tripDuration * 10) * 0.1);
        env.put(sw.getParam1(), divide(speedRange1, tripDuration));
        env.put(sw.getParam2(), divide(speedRange2, tripDuration));
        env.put(sw.getParam3(), divide(speedRange3, tripDuration));
        env.put(sw.getParam4(), divide(speedRange4, tripDuration));
        env.put(sw.getParam5(), divide(speedRange5, tripDuration));
        env.put(sw.getParam6(), divide(speedRange6, tripDuration));
        return (Double) compiled.getExpression().execute(env);
    }
    // 档位
    private Double gears(ScoreWeightCompiled compiled, OuterStatisticData tripData){
        Map<String, Object> env = new HashMap<>();
        ScoreWeight sw = compiled.getScoreWeight();
        // 获取最高档+次高档时长
        Integer duration = null;
        logger.error("trip:{}",tripData.toString());
        if((tripData.getGear16Number() == null?0:tripData.getGear16Number()) > 0
                || (tripData.getGear15Number() == null?0:tripData.getGear15Number()) > 0){
            duration = plus(tripData.getGear16Duration() , tripData.getGear15Duration());
        } else if((tripData.getGear14Number() == null?0:tripData.getGear14Number()) > 0
                || (tripData.getGear13Number() == null?0:tripData.getGear13Number()) > 0){
            duration = plus(tripData.getGear14Duration() + tripData.getGear13Duration());
        } else if((tripData.getGear12Number() == null?0:tripData.getGear12Number()) > 0
                || (tripData.getGear11Number() == null?0:tripData.getGear11Number()) > 0){
            duration = plus(tripData.getGear12Duration() + tripData.getGear11Duration());
        }
        Integer tripDuration = tripData.getTripDuration();
        if(duration == null || tripDuration == null || tripDuration == 0) return null;
        // 本次行程平均油耗
//        env.put(sw.getParam1(), Math.round(duration / tripDuration * 10) * 0.1);
        env.put(sw.getParam1(), divide(duration, tripDuration));
        // 同车型平均油耗：全平台相同车型的历史平均百公里油耗（该值为动态值），暂时默认使用空载30L/100km、半载35L/100km、满载40L/100km。
        return (Double) compiled.getExpression().execute(env);
    }
    // 同车型油耗
    private Double carTypeFule(ScoreWeightCompiled compiled, OuterStatisticData tripData){
        Map<String, Object> env = new HashMap<>();
        ScoreWeight sw = compiled.getScoreWeight();
        int avgFuel = tripData.fuel100KM();
        double avgCarType;
        String loadCode = sw.getLoad_code();
        LoadStatusEnum status = LoadStatusEnum.getEnum(loadCode);
        // 同车型平均油耗：全平台相同车型的历史平均百公里油耗（该值为动态值），暂时默认使用空载30L/100km、半载35L/100km、满载40L/100km。
        if(status != null) {
            switch (status) {
                case EMPTY_LOAD:
                    avgCarType = 30;
                    break;
                case HALF_LOAD:
                    avgCarType = 35;
                    break;
                case FULL_LOAD:
                    avgCarType = 40;
                    break;
                    // 超载使用满载阈值
                case OVER_LOAD:
                    avgCarType = 40;
                    break;
                default:
                    // 默认使用半载阈值
                    avgCarType = 35;
            }
        } else {
            // 默认使用半载阈值
            avgCarType = 35;
        }
        // 平均油耗/同型车平均油耗 占比
        env.put(sw.getParam1(), divide(avgFuel,avgCarType));
        return (Double) compiled.getExpression().execute(env);
    }
    private double divide(Integer a, Integer b){
        if(a == null || b == null) return 0;
        return BigDecimalUtils.divide(a, b ,3).doubleValue();
    }
    private double divide(Integer a, Double b){
        if(a == null || b == null) return 0;
        return BigDecimalUtils.divide(Double.valueOf(a), b ,3).doubleValue();
    }
    private double divide(Double a, Double b){
        if(a == null || b == null) return 0;
        return BigDecimalUtils.divide(a, b ,3).doubleValue();
    }
    private Integer plus(Integer... args){
        int r = 0;
        boolean isEnable = false;
        for(Integer temp:args){
            if(temp == null) continue;
            r+= temp;
            isEnable = true;
        }
        if(isEnable) return r;
        return null;
    }
}
